#ifndef __THREAD_H
#define __THREAD_H
#include"stdint.h"
#include"list.h"
#include"memory.h"

#define STACK_MAGIC 0x20220415
#define SYSTEM_MAX_FILE_OPEN_CNT 32
#define TASK_MAX_FD_CNT 8

typedef int16_t pid_t;

typedef void (*thread_func)(void*);

typedef enum{
	TASK_RUNNING,
	TASK_READY,
	TASK_BLOCKED,
	TASK_WAITING,
	TASK_HANGING,
	TASK_DIED
}task_status;

//interrupt stack for task return from kernal to user mode
typedef struct{
	uint32_t vec_no;
	uint32_t edi;
	uint32_t esi;
	uint32_t ebp;
	uint32_t esp_dummpy;
	uint32_t ebx;
	uint32_t edx;
	uint32_t ecx;
	uint32_t eax;
	uint32_t fs;
	uint32_t gs;
	uint32_t es;
	uint32_t ds;
	uint32_t error_code;
	//these reg is push by cpu staff
	void (* eip)(void);
	uint32_t cs;
	uint32_t eflags;
	uint32_t esp;
	uint32_t ss;
}intr_stack;

//thread stack save thread running context
typedef struct{
	uint32_t ebp;
	uint32_t ebx;
	uint32_t edi;
	uint32_t esi;
	void* ip;
	uint32_t unused_retaddr;
	thread_func function;
	void* args;
}thread_stack;

//kernal thread page dir is NULL
typedef struct{
	uint32_t* k_stack;
	//self task id
	pid_t pid;
	//parent task id
	pid_t ppid;
	task_status status;
	int32_t exit_status;
	uint32_t priority;
	uint32_t tick;
	char name[16];
	virtual_addr_pool process_vaddr_pool;
	mem_bank process_mm_bank;
	uint32_t* page_dir;
	//current work dirctory inode number
	uint32_t cwd_i_no; 
	int32_t fd_table[TASK_MAX_FD_CNT];
	list_elem gen_tag;
	list_elem all_tag;
	//kernal stack should not reach stack magic otherwise the stack is overflow
	uint32_t stack_magic;
}task_tcb;

typedef struct{
	thread_func func;
	const char* name;
	uint32_t priority;
	void* args;
}thread_des;

void init_kernal_thread(void);

void thread_init(thread_des*,task_tcb*);

void thread_create(thread_des*,task_tcb*);

task_tcb* thread_start(thread_des*);

task_tcb* current_thread(void);

void active_page_dir(task_tcb*);

void schedule(void);

void thread_block(task_status ts);

void thread_unblock(task_tcb* thread);

void thread_yield(void);

void thread_exit(task_tcb* thread,bool need_schedule);

char* sys_getcwd(char* iobuffer,uint32_t size);

int32_t sys_chdir(const char* path);

pid_t alloc_pid(char* task_name);

void release_pid(pid_t);

pid_t sys_getpid(void);

void sys_ps(void);

task_tcb* pid2thread(pid_t pid);

task_tcb* find_hanging_child(task_tcb*);

task_tcb* find_child(task_tcb*);

void child_adopt(task_tcb*);

#endif
